import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;
import com.infomatiq.jsi.rtree.RTree;
import com.mongodb.DBObject;
import com.mongodb.Mongo;


public class MongoDAO {

	private static MongoDAO instance;
	public Mongo mongo;
	public Morphia morphia;
	public static Datastore userStore;
	public static Datastore messageStore;
	public static Datastore locationTree;
	private boolean exists = true;
	protected MongoDAO() {	   
		try {
			mongo = new Mongo();
			morphia = new Morphia();
			morphia.map(User.class).map(User.UserData.class);
			///	morphia.map(Message.class).map(Message.MessageData.class);
			userStore = morphia.createDatastore(mongo, "userDB");
			messageStore = morphia.createDatastore(mongo, "messageDB");
			//  locationTree = morphia.createDatastore(mongo, "locationTree");

		} catch (UnknownHostException e) {
			System.out.println("Cannot create database");
		}
		User.UserData q;
		try{
			q = userStore.createQuery(User.UserData.class).get();
		}catch(Exception e)
		{
			System.out.println("There are no users in the database.");
		}

	}
	public static MongoDAO getInstance() {		   
		if(instance == null) {
			instance = new MongoDAO();
		}
		return instance;
	}
	public void AddUser(User u)
	{
		userStore.save(u.data);
	}
	/*public void AddMessage(Message s)
	   {
		   messageStore.save(s.data);
	   }
	   public List<Message> GetAllMessages()
	   {
		   List<Message.MessageData> messageD = messageStore.createQuery(Message.MessageData.class).asList();
			List<Message> messages = new ArrayList<Message>(0);
			for (Message.MessageData u : messageD)
			{
				Message k = new Message(u.rootSender, u.destination, u.messageData, u.iterationsLeft);

			}
			return messages;

	   }*/
	public List<User> GetAllUsers()
	{
		List<User.UserData> usersD = userStore.createQuery(User.UserData.class).asList();
		List<User> users = new ArrayList<User>(0);
		for (User.UserData u : usersD)
		{
			User k = new User(u.identity, u.nickname, u.location);
			k.messages = u.messages;
			k.region = u.region;
			users.add(k);
		}
		return users;
	}
	public User GetNearestUser(Location location, User user)
	{
		List<User> randomUsers = GetUsersInRegion(location.region, 10); //returns 10 users in the region.
		return LocationProcessing.getInstance().FindNearestUser(randomUsers, location, user);
	}
	
	public User UserDataToUser(User.UserData data)
	{
		User s = new User(data.identity, data.nickname, data.location);
		s.messages = data.messages;
		s.region = data.region;
		return s;
	}
	
	private List<User> GetUsersInRegion(int region, int number) {
		// TODO Auto-generated method stub
		List<User.UserData> usersD = userStore.createQuery(User.UserData.class).field("region").equal(region).asList();
		List<User> users = new ArrayList<User>(0);
		for (User.UserData u : usersD)
		{
			
			users.add(UserDataToUser(u));
		}
		return users;
	}
	public User GetUserById(String string) {
		User.UserData usD = null;
		User user = null;
		try{
		usD = userStore.get(User.UserData.class, string);
		user = UserDataToUser(usD);
		}catch(NullPointerException e)
		{
		System.out.println("There is no user in the database with that ID");
		}
		return user;
	}
	public User GetUserByNickName(String string) {
		Query<User.UserData> query = userStore.createQuery(User.UserData.class).field("nickname").equal(string);
		User.UserData usD = null;
		try{
		usD = query.get();
		}catch(NullPointerException e)
		{
			System.out.println("There is no user in the database with that nickname");
		}
		/*User k = new User(usD.identity, usD.nickname, usD.location);
		k.messages = usD.messages;
		k.region = usD.region;*/
		return UserDataToUser(usD);
	}
	public void UpdateUser(User user) {
		Query<User.UserData> updateQuery = userStore.createQuery(User.UserData.class).field("identity").equal(user.identity);
		/*UpdateOperations<User.UserData> ops;
		//getDatastore().getKey(user);
		ops = userStore.createUpdateOperations(User.UserData.class).set("messages", userStore.get(User.UserData.class, user.identity));
		userStore.update(updateQuery, ops);
		ops = userStore.createUpdateOperations(User.UserData.class).set("location", user.location);
		userStore.update(updateQuery, ops);
		ops = userStore.createUpdateOperations(User.UserData.class).set("region", user.region);
		userStore.update(updateQuery, ops);*/
		userStore.delete(updateQuery);
		userStore.save(user.data);
	}


}
